#include "Bat.h"
#include "Level.h"
#include "Bonus.h"
#include "Bass.h"
#include "Ball.h"

//constants definitions:
const float CBat::sc_fMinLength = 3.0f;
const float CBat::sc_fMaxLength = 6.0f;

GLuint CBat::m_uiTexture = 0;
CModel* CBat::m_pModelLeft = NULL;
CModel* CBat::m_pModelMiddle = NULL;
CModel* CBat::m_pModelRight= NULL;

CBat::CBat(float3 f3Position, double3 d3Color)
{
	//non-ODE init routines:
	m_bMarked = false;		//not marked to delete
	m_fLength = 3.0f;		//length of an Bat
	m_fDestLength = m_fLength;	//destination length - used when changing length

	//material:
	m_matMaterial.d3Diffuse = d3Color;
	m_matMaterial.d3Specular = double3(0.0, 0.0, 0.0);
	m_matMaterial.dAlpha = 0.0;
	m_matMaterial.dShiness = 00.0;

	//bonuses init routines:
	m_fStickyTime = 0.0;
	m_bCanClone = false;

	m_fSpeed = 7.0f;	//speed in units/sec.

	m_bOver = false;

	m_pCamera = new CCamera(this);

	//player specific routines:
	m_iLives = 3;
	m_liScore = 0;
	m_iRelease = 0;

	//ODE init routines:
	m_body = dBodyCreate( m_pPhysics->GetWorld() );
		
	m_geom = dCreateBox(m_pPhysics->GetSpace(), m_fLength, 1.0, 1.0);
		
	dGeomSetBody(m_geom, m_body);

	dMassSetBox(&m_mass, 10, m_fLength, 1.0f, 1.0f);
	dBodySetMass(m_body, &m_mass);

	m_jointTrack = 0;

	SetInitialPos(f3Position);

	dBodySetData(m_body, this);
}

CBat::~CBat(void)
{
	dBodyDestroy(m_body);
	dGeomDestroy(m_geom);
	delete m_pCamera;
}

void CBat::SetInitialPos(float3 f3Position)
{
	//position of camera - behind the player
	float3 f3CamPosition = f3Position*1.7f;
	f3CamPosition.y += 14.0f;

	float3 f3CamTarget = f3Position*0.5f;

	m_pCamera->SetPosition(f3CamPosition);
	m_pCamera->SetTarget(f3CamTarget);	//look on the board-center

	//set body position
	dBodySetPosition(m_body, f3Position.x, f3Position.y, f3Position.z);

	if(m_jointTrack)
	{
		dJointDestroy(m_jointTrack);
		m_jointTrack = 0;
	}

	//create track joint
	m_jointTrack = dJointCreateSlider(m_pPhysics->GetWorld(), 0);
	dJointAttach(m_jointTrack, m_body, 0);
	dJointSetSliderAxis(m_jointTrack, 1.0f, 0.0f, 0.0f);
}

int CBat::SetupMatrices(float3 f3Translation, float3 f3Scale)
{
	double dMatrix[16];
	SetTransform(dMatrix, dBodyGetPosition(m_body), dBodyGetRotation(m_body));
	//apply transformations
	dMatrix[12] += f3Translation.x;
	dMatrix[13] += f3Translation.y;
	dMatrix[14] += f3Translation.z;

	dMatrix[0] *= f3Scale.x;
	dMatrix[1] *= f3Scale.x;
	dMatrix[2] *= f3Scale.x;
	dMatrix[4] *= f3Scale.y;
	dMatrix[5] *= f3Scale.y;
	dMatrix[6] *= f3Scale.y;
	dMatrix[8] *= f3Scale.z;
	dMatrix[9] *= f3Scale.z;
	dMatrix[10] *= f3Scale.z;
	//save this model matrix in renderer
	m_pRenderer->SetModelMatrix(dMatrix);
	
	glMultMatrixd (dMatrix);

	return 0;
}

int CBat::Draw()
{
	glPushMatrix();

	m_pRenderer->SetMaterial(m_matMaterial);
	SetupMatrices(float3(0.0f, 0.0f, 0.0f), float3(m_fLength-2.0f, 1.0f, 1.0f));
	m_pModelMiddle->DrawModel();
	SetupMatrices(float3(-(m_fLength/2 - 0.5f), 0.0f, 0.0f), float3(1.0f, 1.0f, 1.0f));
	m_pModelLeft->DrawModel();
	SetupMatrices(float3( (m_fLength/2 - 0.5f), 0.0f, 0.0f), float3(-1.0f, 1.0f, 1.0f));
	m_pModelLeft->DrawModel();

	glPopMatrix();
	return 0;
}

int CBat::MoveLeft()
{
	const double* dCurrPos = dBodyGetPosition(m_body);
	double dNewX = dCurrPos[0] - (m_fSpeed * g_fTime);
	//keep the bat inside board
	if(dNewX < (-m_pLevel->GetWidth()/2 + m_fLength/2))
	{
		dNewX = (-m_pLevel->GetWidth()/2 + m_fLength/2);
	}
	dBodySetPosition(m_body, dNewX, dCurrPos[1], dCurrPos[2]);

	return 0;
}

int CBat::MoveRight()
{
	const double* dCurrPos = dBodyGetPosition(m_body);
	double dNewX = dCurrPos[0] + (m_fSpeed * g_fTime);
	//keep the bat inside board
	if(dNewX > (m_pLevel->GetWidth()/2 - m_fLength/2))
	{
		dNewX = (m_pLevel->GetWidth()/2 - m_fLength/2);
	}
	dBodySetPosition(m_body, dNewX, dCurrPos[1], dCurrPos[2]);

	return 0;
}

int CBat::Fail()
{
	if(m_pDrawList->GetBallCount() == 1)
	{
		m_iLives --;
		if(m_iLives < 0)
			m_bOver = true;
	}

	return 0;
}

int CBat::Update()
{

	if(m_bOver)
	{
		return -1;	//if player has no more lives, return -1 to tell, that game is over
	}

	//control bonus behavior;

	//length control:
	if(m_fDestLength > sc_fMaxLength)
	{
		m_fDestLength = sc_fMaxLength;
	}
	if(m_fLength < m_fDestLength)
	{
		m_fLength += g_fTime;
	}
	if(m_fLength > m_fDestLength)
	{
		m_fLength -= g_fTime;
	}
	//adjust geom length
	double3 d3Result;
	dGeomBoxGetLengths(m_geom, d3Result.pos);
	d3Result.x = m_fLength;
	dGeomBoxSetLengths(m_geom, d3Result.x, d3Result.y, d3Result.z);

	//stick control:
	if(m_fStickyTime > 0.0f)
	{
		m_fStickyTime -= g_fTime;
	}


	return 0;
}

int CBat::Score(int iValue)
{
	m_liScore += iValue;
	return 0;
}

void CBat::SetRelease(bool bRelease)
{
	if(bRelease)
	{
		m_iRelease = m_pDrawList->GetBallCount();	//release all balls
	}
	else
	{
		if(m_iRelease > 0)
		{
			m_iRelease--;	//one ball released
		}
	}
}

int CBat::ApplyBonus(CBonus* pBonus)
{
	Score(pBonus->GetValue());
	switch(pBonus->GetBonusType())
	{
		case BT_EXPAND:
			Expand();
			m_pSoundManager->PlaySoundA("data\\sounds\\snake.wav",false);
			break;
		case BT_STICK:
			EnableStick();
			m_pSoundManager->PlaySoundA("data\\sounds\\hedgehog.wav",false);
			break;
		case BT_CLONE:
			EnableClone(true);
			m_pSoundManager->PlaySoundA("data\\sounds\\sheep.wav",false);
			break;
	}
	return 0;
}

int CBat::ResetBonuses()
{
	m_fLength = m_fDestLength = sc_fMinLength;
	m_fStickyTime = 0.0f;
	m_bCanClone = false;
	return 0;
}

void CBat::Expand()
{
	m_fDestLength += 1.0f;
}

void CBat::EnableStick()
{
	m_fStickyTime = 30.0f;
}

void CBat::EnableClone(bool bEnabled)
{
	CBall::EnableClone(bEnabled);
}

bool CBat::CanClone()
{
	return m_bCanClone;
}

bool CBat::IsSticky()
{
	return (m_fStickyTime > 0.0f);
}

/****************************************************************************/
/* Enable/disable dynamic camera                                            */
/****************************************************************************/
void CBat::SwitchDynamicCamera(bool bEnabled)
{
	m_pCamera->SetDynamic(bEnabled);
}

void CBat::LoadTexture()
{
	m_uiTexture = CUtils::LoadRAW("data\\images\\boat.raw", 256, 256);
}
